home *** CD-ROM | disk | FTP | other *** search
- /*****************************************************************************
- * fractal.c
- *
- * This module implements the fractal sets primitive.
- *
- * This file was written by Pascal Massimino.
- *
- * from Persistence of Vision(tm) Ray Tracer
- * Copyright 1996 Persistence of Vision Team
- *---------------------------------------------------------------------------
- * NOTICE: This source code file is provided so that users may experiment
- * with enhancements to POV-Ray and to port the software to platforms other
- * than those supported by the POV-Ray Team. There are strict rules under
- * which you are permitted to use this file. The rules are in the file
- * named POVLEGAL.DOC which should be distributed with this file. If
- * POVLEGAL.DOC is not available or for more info please contact the POV-Ray
- * Team Coordinator by leaving a message in CompuServe's Graphics Developer's
- * Forum. The latest version of POV-Ray may be found there as well.
- *
- * This program is based on the popular DKB raytracer version 2.12.
- * DKBTrace was originally written by David K. Buck.
- * DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins.
- *
- *****************************************************************************/
-
- #include "frame.h"
- #include "povray.h"
- #include "vector.h"
- #include "povproto.h"
- #include "bbox.h"
- #include "matrices.h"
- #include "objects.h"
- #include "spheres.h"
- #include "fractal.h"
- #include "quatern.h"
- #include "hcmplx.h"
-
-
-
- /*****************************************************************************
- * Local preprocessor defines
- ******************************************************************************/
-
- #ifndef Fractal_Tolerance
- #define Fractal_Tolerance 1e-7
- #endif
-
-
-
- /*****************************************************************************
- * Local typedefs
- ******************************************************************************/
-
-
-
- /*****************************************************************************
- * Static functions
- ******************************************************************************/
-
- static int All_Fractal_Intersections PARAMS((OBJECT * Object, RAY * Ray, ISTACK * Depth_Stack));
- static int Inside_Fractal PARAMS((VECTOR IPoint, OBJECT * Object));
- static void Fractal_Normal PARAMS((VECTOR Result, OBJECT * Object, INTERSECTION * Intersect));
- static void *Copy_Fractal PARAMS((OBJECT * Object));
- static void Translate_Fractal PARAMS((OBJECT * Object, VECTOR Vector, TRANSFORM *Trans));
- static void Rotate_Fractal PARAMS((OBJECT * Object, VECTOR Vector, TRANSFORM *Trans));
- static void Scale_Fractal PARAMS((OBJECT * Object, VECTOR Vector, TRANSFORM *Trans));
- static void Transform_Fractal PARAMS((OBJECT * Object, TRANSFORM * Trans));
- static void Invert_Fractal PARAMS((OBJECT * Object));
- static void Destroy_Fractal PARAMS((OBJECT * Object));
- static void Compute_Fractal_BBox PARAMS((FRACTAL * Fractal));
-
- /*****************************************************************************
- * Local variables
- ******************************************************************************/
-
- static METHODS Fractal_Methods =
- {
- All_Fractal_Intersections,
- Inside_Fractal, Fractal_Normal,
- Copy_Fractal,
- Translate_Fractal, Rotate_Fractal,
- Scale_Fractal, Transform_Fractal, Invert_Fractal,
- Destroy_Fractal
- };
-
- static int Allocated_Iteration_Stack_Length = 0;
-
- DBL *Sx = NULL, *Sy = NULL, *Sz = NULL, *Sw = NULL;
- DBL Precision;
- VECTOR Direction;
-
- static COMPLEX_FUNCTION_METHOD Complex_Function_List[] =
- {
- /* must match STYPE list in fractal.h */
- Complex_Exp,
- Complex_Log,
- Complex_Sin,
- Complex_ASin,
- Complex_Cos,
- Complex_ACos,
- Complex_Tan,
- Complex_ATan,
- Complex_Sinh,
- Complex_ASinh,
- Complex_Cosh,
- Complex_ACosh,
- Complex_Tanh,
- Complex_ATanh,
- Complex_Pwr
- };
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Pascal Massimino
- *
- * DESCRIPTION
- *
- * -
- *
- * CHANGES
- *
- * Dec 1994 : Creation.
- *
- ******************************************************************************/
-
- static int All_Fractal_Intersections(Object, Ray, Depth_Stack)
- OBJECT *Object;
- RAY *Ray;
- ISTACK *Depth_Stack;
- {
- int Intersection_Found;
- int Last = 0;
- int CURRENT, NEXT;
- DBL Depth, Depth_Max;
- DBL Dist, Dist_Next, Len;
-
- VECTOR IPoint, Mid_Point, Next_Point, Real_Pt;
- VECTOR Real_Normal, F_Normal;
- RAY New_Ray;
- FRACTAL *Fractal = (FRACTAL *) Object;
-
- Increase_Counter(stats[Ray_Fractal_Tests]);
-
- Intersection_Found = FALSE;
- Precision = Fractal->Precision;
-
- /* Get into Fractal's world. */
-
- if (Fractal->Trans != NULL)
- {
- MInvTransDirection(Direction, Ray->Direction, Fractal->Trans);
- VDot(Len, Direction, Direction);
-
- if (Len == 0.0)
- {
- return (FALSE);
- }
-
- if (Len != 1.0)
- {
- Len = 1.0 / sqrt(Len);
- VScaleEq(Direction, Len);
- }
-
- Assign_Vector(New_Ray.Direction, Direction);
- MInvTransPoint(New_Ray.Initial, Ray->Initial, Fractal->Trans);
- }
- else
- {
- Assign_Vector(Direction, Ray->Direction);
- New_Ray = *Ray;
- Len = 1.0;
- }
-
- /* Bound fractal. */
-
- if (!F_Bound(&New_Ray, Fractal, &Depth, &Depth_Max))
- {
- return (FALSE);
- }
-
- if (Depth_Max < Fractal_Tolerance)
- {
- return (FALSE);
- }
-
- if (Depth < Fractal_Tolerance)
- {
- Depth = Fractal_Tolerance;
- }
-
- /* Jump to starting point */
-
- VScale(Next_Point, Direction, Depth);
- VAddEq(Next_Point, New_Ray.Initial);
-
- CURRENT = D_Iteration(Next_Point, Fractal, &Dist);
-
- /* Light ray starting inside ? */
-
- if (CURRENT)
- {
- VAddScaledEq(Next_Point, 2.0 * Fractal_Tolerance, Direction);
-
- Depth += 2.0 * Fractal_Tolerance;
-
- if (Depth > Depth_Max)
- {
- return (FALSE);
- }
-
- CURRENT = D_Iteration(Next_Point, Fractal, &Dist);
- }
-
- /* Ok. Trace it */
-
- while (Depth < Depth_Max)
- {
- /*
- * Get close to the root: Advance with Next_Point, keeping track of last
- * position in IPoint...
- */
-
- while (1)
- {
- if (Dist < Precision)
- {
- Dist = Precision;
- }
-
- Depth += Dist;
-
- if (Depth > Depth_Max)
- {
- if (Intersection_Found)
- {
- Increase_Counter(stats[Ray_Fractal_Tests_Succeeded]);
- }
-
- return (Intersection_Found);
- }
-
- Assign_Vector(IPoint, Next_Point);
- VAddScaledEq(Next_Point, Dist, Direction);
-
- NEXT = D_Iteration(Next_Point, Fractal, &Dist_Next);
-
- if (NEXT != CURRENT)
- {
- /* Set surface was crossed... */
-
- Depth -= Dist;
- break;
- }
- else
- {
- Dist = Dist_Next; /* not reached */
- }
- }
-
- /* then, polish the root via bisection method... */
-
- while (Dist > Fractal_Tolerance)
- {
- Dist *= 0.5;
- VAddScaled(Mid_Point, IPoint, Dist, Direction);
-
- Last = Iteration(Mid_Point, Fractal);
-
- if (Last == CURRENT)
- {
- Assign_Vector(IPoint, Mid_Point);
-
- Depth += Dist;
-
- if (Depth > Depth_Max)
- {
- if (Intersection_Found)
- {
- Increase_Counter(stats[Ray_Fractal_Tests_Succeeded]);
- }
-
- return (Intersection_Found);
- }
- }
- }
-
- if (CURRENT == FALSE) /* Mid_Point isn't inside the set */
- {
- VAddScaledEq(IPoint, Dist, Direction);
-
- Depth += Dist;
-
- Iteration(IPoint, Fractal);
- }
- else
- {
- if (Last != CURRENT)
- {
- Iteration(IPoint, Fractal);
- }
- }
-
- if (Fractal->Trans != NULL)
- {
- MTransPoint(Real_Pt, IPoint, Fractal->Trans);
- Normal_Calc(Fractal, F_Normal);
- MTransNormal(Real_Normal, F_Normal, Fractal->Trans);
- }
- else
- {
- Assign_Vector(Real_Pt, IPoint);
- Normal_Calc(Fractal, Real_Normal);
- }
-
- if (Point_In_Clip(Real_Pt, Object->Clip))
- {
- VNormalize(Real_Normal, Real_Normal);
- push_normal_entry(Depth * Len, Real_Pt, Real_Normal, Object, Depth_Stack);
- Intersection_Found = TRUE;
-
- /* If fractal isn't used with CSG we can exit now. */
-
- if (!(Fractal->Type & IS_CHILD_OBJECT))
- {
- break;
- }
- }
-
- /* Start over where work was left */
-
- Assign_Vector(IPoint, Next_Point);
- Dist = Dist_Next;
- CURRENT = NEXT;
-
- }
-
- if (Intersection_Found)
- {
- Increase_Counter(stats[Ray_Fractal_Tests_Succeeded]);
- }
- return (Intersection_Found);
- }
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Pascal Massimino
- *
- * DESCRIPTION
- *
- * -
- *
- * CHANGES
- *
- * Dec 1994 : Creation.
- *
- ******************************************************************************/
-
- static int Inside_Fractal(IPoint, Object)
- VECTOR IPoint;
- OBJECT *Object;
- {
- FRACTAL *Fractal = (FRACTAL *) Object;
- int Result;
- static VECTOR New_Point;
-
- if (Fractal->Trans != NULL)
- {
- MInvTransPoint(New_Point, IPoint, Fractal->Trans);
-
- Result = Iteration(New_Point, Fractal);
- }
- else
- {
- Result = Iteration(IPoint, Fractal);
- }
-
- if (Fractal->Inverted)
- {
- return (!Result);
- }
- else
- {
- return (Result);
- }
- }
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Pascal Massimino
- *
- * DESCRIPTION
- *
- * -
- *
- * CHANGES
- *
- * Dec 1994 : Creation.
- *
- ******************************************************************************/
-
- static void Fractal_Normal(Result, Object, Intersect)
- OBJECT *Object;
- VECTOR Result;
- INTERSECTION *Intersect;
- {
- Assign_Vector(Result, Intersect->INormal);
- }
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Pascal Massimino
- *
- * DESCRIPTION
- *
- * -
- *
- * CHANGES
- *
- * Dec 1994 : Creation.
- *
- ******************************************************************************/
-
- static void Translate_Fractal(Object, Vector, Trans)
- OBJECT *Object;
- VECTOR Vector;
- TRANSFORM *Trans;
- {
- Transform_Fractal(Object, Trans);
- }
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Pascal Massimino
- *
- * DESCRIPTION
- *
- * -
- *
- * CHANGES
- *
- * Dec 1994 : Creation.
- *
- ******************************************************************************/
-
- static void Rotate_Fractal(Object, Vector, Trans)
- OBJECT *Object;
- VECTOR Vector;
- TRANSFORM *Trans;
- {
- Transform_Fractal(Object, Trans);
- }
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Pascal Massimino
- *
- * DESCRIPTION
- *
- * -
- *
- * CHANGES
- *
- * Dec 1994 : Creation.
- *
- ******************************************************************************/
-
- static void Scale_Fractal(Object, Vector, Trans)
- OBJECT *Object;
- VECTOR Vector;
- TRANSFORM *Trans;
- {
- Transform_Fractal(Object, Trans);
- }
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Pascal Massimino
- *
- * DESCRIPTION
- *
- * -
- *
- * CHANGES
- *
- * Dec 1994 : Creation.
- * Mar 1996 : Moved call to Recompute_BBox to Compute_Fractal_BBox() (TW)
- *
- ******************************************************************************/
-
- static void Transform_Fractal(Object, Trans)
- OBJECT *Object;
- TRANSFORM *Trans;
- {
- FRACTAL *Fractal = (FRACTAL *) Object;
-
- if (((FRACTAL *) Object)->Trans == NULL)
- {
- ((FRACTAL *) Object)->Trans = Create_Transform();
- }
-
- Compose_Transforms(Fractal->Trans, Trans);
-
- Compute_Fractal_BBox((FRACTAL *) Object);
- }
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Pascal Massimino
- *
- * DESCRIPTION
- *
- * -
- *
- * CHANGES
- *
- * Dec 1994 : Creation.
- *
- ******************************************************************************/
-
- static void Invert_Fractal(Object)
- OBJECT *Object;
- {
- ((FRACTAL *) Object)->Inverted ^= TRUE;
- }
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Pascal Massimino
- *
- * DESCRIPTION
- *
- * -
- *
- * CHANGES
- *
- * Dec 1994 : Creation.
- * Mar 1996 : Added call to recompute_BBox() to bottom (TW)
- *
- ******************************************************************************/
-
- static void Compute_Fractal_BBox(Fractal)
- FRACTAL *Fractal;
- {
- DBL R;
-
- switch (Fractal->Algebra)
- {
- case QUATERNION_TYPE:
-
- R = 1.0 + sqrt(Sqr(Fractal->Julia_Parm[X]) + Sqr(Fractal->Julia_Parm[Y]) + Sqr(Fractal->Julia_Parm[Z]) + Sqr(Fractal->Julia_Parm[T]));
- R += Fractal_Tolerance; /* fix bug when Julia_Parameter exactly 0 */
-
- if (R > 2.0)
- {
- R = 2.0;
- }
-
- Fractal->Exit_Value = Sqr(R);
-
- break;
-
- case HYPERCOMPLEX_TYPE:
- default:
-
- R = 4.0;
-
- Fractal->Exit_Value = 16.0;
-
- break;
- }
-
- Fractal->Radius_Squared = Sqr(R);
-
- Fractal->Inverted = FALSE;
-
- Make_BBox(Fractal->BBox, -R, -R, -R, 2.0 * R, 2.0 * R, 2.0 * R);
-
- Recompute_BBox(&Fractal->BBox, Fractal->Trans);
- }
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Pascal Massimino
- *
- * DESCRIPTION
- *
- * -
- *
- * CHANGES
- *
- * Dec 1994 : Creation.
- *
- ******************************************************************************/
-
- FRACTAL *Create_Fractal()
- {
- FRACTAL *New;
-
- New = (FRACTAL *) POV_MALLOC(sizeof(FRACTAL), "Fractal Set");
-
- INIT_OBJECT_FIELDS(New, BASIC_OBJECT, &Fractal_Methods)
-
- New->Trans = NULL;
-
- Make_Vector(New->Center, 0.0, 0.0, 0.0);
-
- New->Julia_Parm[X] = 1.0;
- New->Julia_Parm[Y] = 0.0;
- New->Julia_Parm[Z] = 0.0;
- New->Julia_Parm[T] = 0.0;
-
- New->Slice[X] = 0.0;
- New->Slice[Y] = 0.0;
- New->Slice[Z] = 0.0;
- New->Slice[T] = 1.0;
- New->SliceDist = 0.0;
-
- New->Exit_Value = 4.0;
-
- New->n = 20;
-
- New->Precision = 1.0 / 20.0;
-
- New->Inverted = FALSE;
-
- New->Algebra = QUATERNION_TYPE;
-
- New->Sub_Type = SQR_STYPE;
-
- New->Bound = NULL;
-
- New->Clip = NULL;
-
- New->Normal_Calc_Method = NULL;
- New->Iteration_Method = NULL;
- New->D_Iteration_Method = NULL;
- New->F_Bound_Method = NULL;
- New->Complex_Function_Method = NULL;
-
- New->Radius_Squared = 0.0;
- New->exponent.x = 0.0;
- New->exponent.y = 0.0;
-
- return (New);
- }
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Pascal Massimino
- *
- * DESCRIPTION
- *
- * -
- *
- * CHANGES
- *
- * Dec 1994 : Creation.
- *
- ******************************************************************************/
-
- static void *Copy_Fractal(Object)
- OBJECT *Object;
- {
- FRACTAL *New;
-
- New = Create_Fractal();
-
- *New = *((FRACTAL *) Object);
-
- New->Trans = Copy_Transform(((FRACTAL *) Object)->Trans);
-
- return (New);
- }
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Pascal Massimino
- *
- * DESCRIPTION
- *
- * -
- *
- * CHANGES
- *
- * Dec 1994 : Creation.
- *
- ******************************************************************************/
-
- static void Destroy_Fractal(Object)
- OBJECT *Object;
- {
- Destroy_Transform(((FRACTAL *) Object)->Trans);
- POV_FREE(Object);
- }
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Pascal Massimino
- *
- * DESCRIPTION
- *
- * -
- *
- * CHANGES
- *
- * Dec 1994 : Creation.
- *
- ******************************************************************************/
-
- void SetUp_Fractal(Fractal)
- FRACTAL *Fractal;
- {
- switch (Fractal->Algebra)
- {
- case QUATERNION_TYPE:
-
- switch(Fractal->Sub_Type)
- {
- case CUBE_STYPE:
- Fractal->Iteration_Method = Iteration_z3;
- Fractal->Normal_Calc_Method = Normal_Calc_z3;
- Fractal->D_Iteration_Method = D_Iteration_z3;
- break;
- case SQR_STYPE:
- Fractal->Iteration_Method = Iteration_Julia;
- Fractal->D_Iteration_Method = D_Iteration_Julia;
- Fractal->Normal_Calc_Method = Normal_Calc_Julia;
- break;
- default:
- Error("illegal function: quaternion only supports sqr and cube");
- }
- Fractal->F_Bound_Method = F_Bound_Julia;
-
- break;
-
- case HYPERCOMPLEX_TYPE:
-
- switch (Fractal->Sub_Type)
- {
- case RECIPROCAL_STYPE:
-
- Fractal->Iteration_Method = Iteration_HCompl_Reciprocal;
- Fractal->Normal_Calc_Method = Normal_Calc_HCompl_Reciprocal;
- Fractal->D_Iteration_Method = D_Iteration_HCompl_Reciprocal;
- Fractal->F_Bound_Method = F_Bound_HCompl_Reciprocal;
-
- break;
-
- case EXP_STYPE:
- case LOG_STYPE:
- case SIN_STYPE:
- case ASIN_STYPE:
- case COS_STYPE:
- case ACOS_STYPE:
- case TAN_STYPE:
- case ATAN_STYPE:
- case SINH_STYPE:
- case ASINH_STYPE:
- case COSH_STYPE:
- case ACOSH_STYPE:
- case TANH_STYPE:
- case ATANH_STYPE:
- case PWR_STYPE:
-
- Fractal->Iteration_Method = Iteration_HCompl_Func;
- Fractal->Normal_Calc_Method = Normal_Calc_HCompl_Func;
- Fractal->D_Iteration_Method = D_Iteration_HCompl_Func;
- Fractal->F_Bound_Method = F_Bound_HCompl_Func;
- Fractal->Complex_Function_Method = Complex_Function_List[Fractal->Sub_Type];
-
- break;
-
- case CUBE_STYPE:
-
- Fractal->Iteration_Method = Iteration_HCompl_z3;
- Fractal->Normal_Calc_Method = Normal_Calc_HCompl_z3;
- Fractal->D_Iteration_Method = D_Iteration_HCompl_z3;
- Fractal->F_Bound_Method = F_Bound_HCompl_z3;
-
- break;
-
- default: /* SQR_STYPE or else... */
-
- Fractal->Iteration_Method = Iteration_HCompl;
- Fractal->Normal_Calc_Method = Normal_Calc_HCompl;
- Fractal->D_Iteration_Method = D_Iteration_HCompl;
- Fractal->F_Bound_Method = F_Bound_HCompl;
-
- break;
- }
-
- break;
-
- default:
-
- Error("Algebra unknown in fractal.");
- }
-
- Allocate_Iteration_Stack(Fractal->n);
-
- Compute_Fractal_BBox(Fractal);
- }
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Pascal Massimino
- *
- * DESCRIPTION
- *
- * -
- *
- * CHANGES
- *
- * Dec 1994 : Creation.
- *
- ******************************************************************************/
-
- void Allocate_Iteration_Stack(n)
- int n;
- {
- if (n > Allocated_Iteration_Stack_Length)
- {
- Sx = (DBL *) POV_REALLOC(Sx, (n + 1) * sizeof(DBL), "x iteration stack");
- Sy = (DBL *) POV_REALLOC(Sy, (n + 1) * sizeof(DBL), "y iteration stack");
- Sz = (DBL *) POV_REALLOC(Sz, (n + 1) * sizeof(DBL), "w iteration stack");
- Sw = (DBL *) POV_REALLOC(Sw, (n + 1) * sizeof(DBL), "z iteration stack");
-
- Allocated_Iteration_Stack_Length = n;
- }
- }
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Pascal Massimino
- *
- * DESCRIPTION
- *
- * -
- *
- * CHANGES
- *
- * Dec 1994 : Creation.
- *
- ******************************************************************************/
-
- void Free_Iteration_Stack()
- {
- if (Sx != NULL)
- {
- POV_FREE(Sx);
- POV_FREE(Sy);
- POV_FREE(Sz);
- POV_FREE(Sw);
- }
-
- Sx = NULL;
- Sy = NULL;
- Sz = NULL;
- Sw = NULL;
-
- Allocated_Iteration_Stack_Length = 0;
- }
-
-
-